﻿//-----------------------------------------------------------------------
// <copyright file="CommunicationBus.cs" company="WpfDevelopment.com">
//     Copyright WpfDevelopment.com. All rights reserved.
// </copyright>
//-----------------------------------------------------------------------
namespace WpfDevelopment.MVVM
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics.Contracts;

    /// <summary>
    /// A communication bus to communicate over
    /// </summary>
    public class CommunicationBus : ICommunicationBus
    {
        /// <summary>
        /// Contains the register of subscribed listeners
        /// </summary>
        private Dictionary<object, List<WeakAction>> register;

        /// <summary>
        /// Initializes a new instance of the <see cref="CommunicationBus"/> class.
        /// </summary>
        public CommunicationBus()
        {
            this.register = new Dictionary<object, List<WeakAction>>();
        }

        /// <summary>
        /// Registers the specified callback to the given message.
        /// </summary>
        /// <typeparam name="T">type of message to send</typeparam>
        /// <param name="message">The message.</param>
        /// <param name="callback">The callback.</param>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1")]
        public void Register<T>(T message, Action<object> callback)
        {
            if (this.register == null) 
            {
                return;
            }

            // Create and or attach to message
            if (!this.register.ContainsKey(message))
            {
                this.register.Add(message, new List<WeakAction>());
            }
            if (this.register[message] != null)
            {
                this.register[message].Add(new WeakAction(callback));
            }
        }

        /// <summary>
        /// Notifies the specified message.
        /// </summary>
        /// <typeparam name="T">type of message to send</typeparam>
        /// <param name="message">The message.</param>
        /// <param name="parameter">The parameter.</param>
        public void Notify<T>(T message, object parameter)
        {
            if (this.register == null)
            {
                return;
            }

            // Check if there are colleagues
            if (!this.register.ContainsKey(message))
            {
                return;
            }

            // Don't notify dead objects
            List<WeakAction> weakActions = this.register[message];
            if (weakActions == null)
            {
                return;
            }
            for (int i = weakActions.Count - 1; i > -1; --i)
            {
                WeakAction weakAction = weakActions[i];
                if (weakAction == null)
                {
                    continue;
                }
                if (!weakAction.IsAlive)
                {
                    weakActions.RemoveAt(i);
                }
                else
                {
                    weakAction.CreateAction().Invoke(parameter);
                }
            }
        }
    }
}
